package com.wargame.engine;

import com.wargame.hexmap.HexagonalMap;
import com.wargame.hexmap.Offset;
import com.wargame.hexmap.Hex;

import java.util.HashMap;
import java.util.Random;

/**
 * @param thisOpr  算子对象
 * @param interact 交互对象
 * @param map      地图对象
 * @param judge    裁决对象
 * @return Object 返回类型为HashMap<String, Object>的裁决信息
 */
public Object ToJudge(Operator thisOpr, Interact interact, HexagonalMap map, HashMap<String, Judge> judgeHandlers) {

    Judge shootJudge = judgeHandlers.get("Shoot");
    Judge canSeeJudge = judgeHandlers.get("CanSee");

    // 被攻击算子信息
    int objID = (int) thisOpr.getAttri("ObjID");
    int blood = (int) thisOpr.getAttri("Blood");
    String color = (String) thisOpr.getAttri("COlor");
    int[] curHex = (int[]) thisOpr.getAttri("CurHex");
    String moveState = (String) thisOpr.getAttri("MoveState");
    String type = (String) thisOpr.getAttri("Type");
    String subType = (String) thisOpr.getAttri("SubType");
    double speed = (double) thisOpr.getAttri("Speed");
    boolean stack = (boolean) thisOpr.getAttri("Stack");
    String armor = (String) thisOpr.gttAttri("Armor");

    // 主动攻击算子信息
    int interactObjID = (int) interact.getAttri("ObjID");
    String interactType = (String) interact.getAttri("Name");
    int interactAttObjID = (int) interact.getAttri("AttObjID");
    int[] interactAttCurHex = (int[]) interact.getAttri("AttCurHex");
    String interactAttColor = (String) interact.getAttri("AttColor");
    String interactAttType = (String) interact.getAttri("AttType");
    String interactWeapon = (String) interact.getAttri("Weapon");
    int interactAttBlood = (int) interact.getAttri("AttBlood");
    boolean interactAttKeep = (boolean) interact.getAttri("AttKeep");
    int interactAttSpeed = (int) interact.getAttri("AttSpeed");
    String interactAttSubType = (String) interact.getAttri("AttSubType");
    HashMap<String, Integer> interactAttObserveDistance = (HashMap<String, Integer>) interact.getAttri("AttObserveDistance");

    // 地图中的 裁决需要用到的属性
    Offset offset = new Offset(curHex[0], curHex[1]); // 被攻击算子的偏移坐标
    Offset attOffset = new Offset(interactAttCurHex[0], interactAttCurHex[1]); // 攻击算子的偏移坐标

    boolean canSee = (boolean) canSeeJudge.toJudge(map, interactType, type, attOffset, offset, interactAttObserveDistance, moveState);
    int distance = map.getDistance(offset, attOffset); // 对阵双方之间的距离
    int elevGrade = map.getElevGrade(); // 地图的高程等差
    Hex attHex = map.get(attOffset); // 攻击者所在位置的六角格信息
    Hex hex = map.get(offset); // 被攻击者所在位置的六角格信息
    int attElev = (int) attHex.getElev("elev"); // 攻击者所处位置的高度
    int elev = (int) hex.getElev("elev"); // 被攻击者所处位置的高度
    int attCond = (int) attHex.getCond("cond"); // 被攻击者所处位置的地形
    int cond = (int) hex.getCond("cond"); // 被攻击者所处位置的地形

    // 两个筛子（两个随机数）
    Random random = new Random();
    int dice1 = random.nextInt(6) + 1;
    int dice2 = random.nextInt(6) + 1;
    int dice3 = random.nextInt(6) + 1;
    int dice4 = random.nextInt(6) + 1;
    int random1 = dice1 + dice2;
    int random2 = dice3 + dice4;

    // 具体的武器装备
    Equipment equipment = (Equipment) thisOpr.getEquipment(interactWeapon);

    // 裁决标志位，压制标志位，射击标志位，算子高度差，攻击等级，裁决信息
    boolean judgeFlag = true;
    boolean flagKeep = false;
    boolean flagShoot = true;
    int elevDiff = 0;
    int attackLevel = 0;
    HashMap<String, Object> judgeInfo = new HashMap<>();
    judgeInfo.put("IsSuccess", false);
    judgeInfo.put("AttObjID", interactAttObjID);
    judgeInfo.put("AttBlood", interactAttBlood);
    judgeInfo.put("AttColor", interactAttColor);
    judgeInfo.put("AttSubType", interactAttSubType);
    judgeInfo.put("Damage", null);
    judgeInfo.put("Distance", null);
    judgeInfo.put("EleDiff", null);
    judgeInfo.put("OriDamage", null);
    judgeInfo.put("Random1", null);
    judgeInfo.put("Random2", null);
    judgeInfo.put("Random2Rect", null);
    judgeInfo.put("RectDamage", null);
    judgeInfo.put("TargetObjID", objID);
    judgeInfo.put("TargetColor", color);
    judgeInfo.put("TargetSubType", subType);
    judgeInfo.put("Type", "Shoot");
    judgeInfo.put("weapon", interactWeapon);
    judgeInfo.put("Keep", null);
    // random2Rect随机数修正值，rectDamage修正损伤，damage最终损伤，originDamage最初损伤
    int random2Rect, rectDamage, damage, originDamage;

    if (!canSee)
        return judgeInfo;

    // 根据被打击者类型的不同查找不同的表来计算攻击等级
    if (type.equals("Vehicle")) { // 直瞄武器对车辆攻击
        // 获得直瞄武器对车辆目标的攻击等级
        int rangeVehicle = (int) equipment.getAttri("RangeVehicle"); //获得该武器对车辆的攻击等级范围
        if (rangeVehicle < 0 || distance > rangeVehicle) {
            judgeFlag = false;
            System.out.println("无效裁决：武器攻击距离小于到目标的距离 或 该武器无法对车辆进行射击");
        } else {
            ArrayList<Integer> attackLevelsVehicle = (ArrayList<Integer>) equipment.getAttri("AttackLevelsVehicle"); //直瞄武器对车辆的攻击等级
            attackLevel = attackLevelsVehicle.get(distance);
        }
        // 未能获得攻击等级
        if (!judgeFlag)
            return judgeInfo;

        // 修正攻击等级
        // 算子之间的高度差: |a算子的高度-b算子的高度| / 地图的 elevGrade
        elevDiff = -(attElev - elev) / elevGrade; // 算子之间的高度差
        int elevRect; // 高差修正值
        if (elevDiff > 8) elevDiff = 8;
        if (elevDiff <= 0 | distance > 12) elevRect = 0; //如果是 高打低 或者 距离远  则不做高差修正
        else {
            String elevRectTable = "ElevRectTable";
            elevRect = (int) shootJudge.getValueFromTable(elevRectTable, elevDiff, distance);
//            elevRect = (int) FileIO.getValueFromCSVRecords(judge.getTable(elevRectTable), elevDiff, distance, judge.getInnerType(elevRectTable));
        }
        if (attackLevel >= -elevRect) attackLevel += elevRect;// 如果攻击等级被修正后大于0则正常修正
        else attackLevel = 0;// 如果小于就修正为0

        // 计算最初的损伤
        // 攻击等级小于等于0，不造成伤害  变量附上初始值用于直接形成裁决结果
        if (attackLevel <= 0) {
            random1 = -1;
            random2 = -1;
            random2Rect = -1;
            originDamage = 0;
            rectDamage = 0;
            damage = -1;
        } else { // 计算originDamage

            // 由血量与攻击等级查其在对应originDamageTab中的列
            String attackLevelToOriDamage = "AttackLevelToOriDamage";

            int originDamageRow = (int) FileIO.getValueFromCSVRecords(judge.getTable(attackLevelToOriDamage), interactAttBlood, attackLevel, judge.getInnerType(attackLevelToOriDamage));
            // 查直瞄武器对车辆单位战斗结果表
            String originDamageTab = "OriginDamageTab";
            originDamage = (int) shootJudge.getValueFromTable(originDamageTab, random1, originDamageRow);
//            originDamage = (int) FileIO.getValueFromCSVRecords(judge.getTable(originDamageTab), random1, originDamageRow, judge.getInnerType(originDamageTab));

            // 随机数修正
            // 计算随机数2修正值random2Rect
            int val = 0;// 记录random2将会被修正多少
            if (interactAttKeep) val -= 1;// 射击算子被压制
            if (interactAttSpeed > 0) val -= 1;//正在机动
            if (interactAttSubType == "Tank" && attCond == 4) val -= 1;  // 如果坦克算子并在水上地形

            // 射击目标在城镇、丛林、河流
            if (cond == 2) val -= 1;
            if (cond == 1) val -= 2;
            if (cond == 4) val -= 2;

            // 射击目标正在掩蔽、机动、堆叠、行军
            if (moveState.equals("Shelt")) val -= 2;
            if (speed > 0) val -= 2;
            if (stack) val += 2;
            if (moveState.equals("March")) val += 4;

            //修正随机数
            random2Rect = random2 + val;

            // 计算最终战损damage
            // 随机数2修正
            int random2RectInd = random2Rect;// random2Rect 限定在-3到12之间，赋值给random2RectInd用于查表,
            if (random2Rect <= -3) random2RectInd = -3;
            else if (random2Rect >= 12) random2RectInd = 12;

            int row = 6;
            switch (armor) {
                case "None":
                    row = 1;
                    break;
                case "Light":
                    row = 2;
                    break;
                case "Medium":
                    row = 3;
                    break;
                case "Heavy":
                    row = 4;
                    break;
                case "Composite":
                    row = 5;
                    break;
            }
            if (row==6){
                System.out.println("无效裁决：目标防护力为未知类型");
                return judgeInfo;
            }

            //战损修正
            String damageRectTab = "DamageRectTab";
            rectDamage = (int) shootJudge.getValueFromTable(damageRectTab, random2RectInd, row);
//            rectDamage = (int) FileIO.getValueFromCSVRecords(judge.getTable(damageRectTab), random2RectInd, row, judge.getInnerType(damageRectTab));
            damage = originDamage + rectDamage;

        }
    } else if (type.equals("Person")) { // 直瞄武器对人员攻击
        // 获得直瞄武器对人员的目标攻击等级
        int rangeInfantry = (int) equipment.getAttri("RangeInfantry"); //获得该武器对人员的攻击等级范围
        if (distance > rangeInfantry) {
            judgeFlag = false;
            System.out.println("无效裁决：武器攻击距离小于到目标的距离");
        } else {
            HashMap<Integer,List<Integer>> attackLevelsInfantry = (HashMap<Integer,List<Integer>>) equipment.getAttri("AttackLevelsInfantry");
            attackLevel = attackLevelsInfantry.get(interactAttBlood).get(distance);

        }
        // 未能获得攻击等级
        if (!judgeFlag)
            return judgeInfo;

        // 计算最初的损伤：直瞄武器对人员/步兵轻武器对车辆战斗结果
        String toInfantryOriDamageTab = "ToInfantryOriDamageTab";
        originDamage = (int) shootJudge.getValueFromTable(toInfantryOriDamageTab, random1, attackLevel);  // TODO
//        originDamage = (int) FileIO.getValueFromCSVRecords(judge.getTable(toInfantryOriDamageTab), random1, attackLevel, judge.getInnerType(toInfantryOriDamageTab));

        if (originDamage == -1) {// damage为-1表示裁决结果damage为0且压制  // 人员才有
            flagKeep = true;// 压制标志位为true
            originDamage = 0;// 战损置为零（没有伤害的纯压制）
        }

        // 随机数修正
        // 计算随机数2修正值random2Rect
        int val = 0;// 记录random2将会被修正多少
        if (interactAttKeep) val -= 1;// 射击算子被压制
        if (interactAttSpeed > 0) val -= 1;//正在机动

        // 射击目标在居民地、丛林、工事
        if (cond == 2) val -= 1;
        if (cond == 1) val -= 2;
//        if (cond == 4) val -= 1;
        // 射击目标正在掩蔽、机动、堆叠、行军
        if (moveState.equals("Shelt")) val -= 2;
        if (speed > 0) val -= 2;
        if (stack) val += 2;
        if (moveState.equals("March")) val += 4;

        //修正随机数
        random2Rect = random2 + val;
        int random2RectInd = random2Rect;
        if (random2Rect <=0) random2RectInd = 0;  //  将random2RectInd限定在0~8之间
        else if (random2Rect >= 8) random2RectInd = 8;

        // 计算最终战损damage
        String toInfantryDamageRectTab = "ToInfantryDamageRectTab";
        rectDamage = (int) shootJudge.getValueFromTable(toInfantryDamageRectTab, random2RectInd, 1);
//        rectDamage = (int) FileIO.getValueFromCSVRecords(judge.getTable(toInfantryDamageRectTab), random2RectInd, 1, judge.getInnerType(toInfantryDamageRectTab));
        damage = originDamage + rectDamage;


    } else {
        judgeFlag = false;
        System.out.println("无效裁决：武器不可攻击该类型");
        return judgeInfo;
    }

    // 如果最终战损damage为0且无压制，为无效射击
    if (damage == 0) {
        if (!flagKeep) {
            damage = -1;
        }
    }
    // 根据上面得到的结果修改judge_info信息
    if (damage < 0) flagShoot = false;// 最终战损小于0为无效射击
    judgeInfo.put("IsSuccess", flagShoot);
    judgeInfo.put("AttObjID", interactAttObjID);
    judgeInfo.put("AttBlood", interactAttBlood);
    judgeInfo.put("AttColor", interactAttColor);
    judgeInfo.put("AttSubType", interactAttSubType);
    judgeInfo.put("Damage", damage);
    judgeInfo.put("Distance", distance);
    judgeInfo.put("EleDiff", elevDiff);
    judgeInfo.put("OriDamage", originDamage);
    judgeInfo.put("Random1", random1);
    judgeInfo.put("Random2", random2);
    judgeInfo.put("Random2Rect", random2Rect);
    judgeInfo.put("RectDamage", rectDamage);
    judgeInfo.put("TargetObjID", objID);
    judgeInfo.put("TargetColor", color);
    judgeInfo.put("TargetSubType", subType);
    judgeInfo.put("Type", "Shoot");
    judgeInfo.put("weapon", interactWeapon);
    judgeInfo.put("Keep", flagKeep || damage > 0);

    return judgeInfo;
}



